/*
  Передача лидера по выходному каналу
*/
inline double transmissionLeaderMS(int flowNumber, double time, int channel) {
  double          &c     = inputData.capacity;
  double          &tPS   = networkSettings.timeMessageSwitching;
  QVector<double> &tRCs  = networkSettings.timeOfReleaseChannels;
  QVector<double> &tTRCs = networkSettings.tempTimeOfReleaseChannels;
  QVector<double> &sMs   = networkSettings.sizeOfMessages;


  if (time + tPS <= tRCs[channel]) {            // если выходной канал занят
    time = tRCs[channel] + sMs[flowNumber] / c; // дождаться освобождения
  } else {
    time += tPS + sMs[flowNumber] / c;          // учесть задержку в узле
  }

  tTRCs[channel] = time;

  return time;
}

/*
  Поиск лидера между двумя претендентами
*/
inline void leaderBetweenTwoMS(double* time1, int* flow1, double time2, int flow2) {
  if (*time1 > time2) {
    *time1 = time2;
    *flow1 = flow2;
  }
}

/*
  Поиск лидера в узле [3]
*/
void leaderForHub3MS(int* flowLeader) {
  double          &t   = networkSettings.currentTime;
  QVector<double> &tMs = networkSettings.timeMessages;

  *flowLeader = 0;
  t = tMs[0];

  double time = -1.0;
  // узел [0]: входной поток [1], выходной канал [0]
  time = transmissionLeaderMS(1, tMs[1], 0);
  leaderBetweenTwoMS(&t, flowLeader, time, 1);

  // узел [1]: входной поток [2], выходной канал [1]
  time = transmissionLeaderMS(2, tMs[2], 1);
  leaderBetweenTwoMS(&t, flowLeader, time, 2);

  // узел [2]: входной поток [3], выходной канал [2]
  time = transmissionLeaderMS(3, tMs[3], 2);
  leaderBetweenTwoMS(&t, flowLeader, time, 3);
}

/*
  Поиск лидера в узле [4]
*/
void leaderForHub4MS(int* flowLeader) {
  double          &t   = networkSettings.currentTime;
  QVector<double> &tMs = networkSettings.timeMessages;

  t = transmissionLeaderMS(*flowLeader, t, 3);

  for (int i = 4; i <= 7; ++i) {
    leaderBetweenTwoMS(&t, flowLeader, tMs[i], i);
  }
}

/*
  Поиск лидера в узле [6]
*/
void leaderForHub6MS(int* flowLeader) {
  double          &t   = networkSettings.currentTime;
  QVector<double> &tMs = networkSettings.timeMessages;

  t = transmissionLeaderMS(*flowLeader, t, 4);

  double time = -1.0;
  // поиск лидера в узле [5]
  int flowLeaderTemp = tMs[8] > tMs[9] ? 9 : 8;
  time = transmissionLeaderMS(flowLeaderTemp, tMs[flowLeaderTemp], 5);

  // поиск лидера в узле [6]
  leaderBetweenTwoMS(&t, flowLeader, time, flowLeaderTemp);

  // поиск лидера в узле [7]
  flowLeaderTemp = tMs[10] > tMs[11] ? 11: 10;
  time = transmissionLeaderMS(flowLeaderTemp, tMs[flowLeaderTemp], 6);

  // повторный поиск лидера в узле [6]
  leaderBetweenTwoMS(&t, flowLeader, time, flowLeaderTemp);
}

/*
  Поиск лидера в узле [9]
*/
void leaderForHub9MS(int* flowLeader) {
  double          &t   = networkSettings.currentTime;
  QVector<double> &tMs = networkSettings.timeMessages;

  t = transmissionLeaderMS(*flowLeader, t, 7);

  double time = -1.0;
  // узел [8]: входной поток [12], выходной канал [8]
  time = transmissionLeaderMS(12, tMs[12], 8);
  leaderBetweenTwoMS(&t, flowLeader, time, 12);

  // узел [10]: входной поток [13], выходной канал [9]
  time = transmissionLeaderMS(13, tMs[13], 9);
  leaderBetweenTwoMS(&t, flowLeader, time, 13);
}

/*
  Поиск лидера в узле [11]
*/
inline void leaderForHub11MS(const int& flowLeader) {
  double &t = networkSettings.currentTime;

  t = transmissionLeaderMS(flowLeader, t, 10);
}

/*
  Поиск общего лидера
*/
void totalLeaderMS(int* flowLeader) {
  leaderForHub3MS(flowLeader);
  leaderForHub4MS(flowLeader);
  leaderForHub6MS(flowLeader);
  leaderForHub9MS(flowLeader);

  // для потоков [1] и [2] узлом назначения является узел [9], для остальных [11]
  if (*flowLeader != 1 && *flowLeader != 2) {
    leaderForHub11MS(*flowLeader);
  }

  if (*flowLeader < 0 || *flowLeader >= numberOfFlows) {
    qFatal("error in totalLeader(): лидер неизвестного потока.");
  }
}

/*
  Освобождение занятых каналов
*/
void clearingOfChannelsMS(const int& flowLeader) {
  QVector<double> &tRCs  = networkSettings.timeOfReleaseChannels;
  QVector<double> &tTRCs = networkSettings.tempTimeOfReleaseChannels;

  switch (flowLeader) {
  case 0: // channels: ->[3]->[4]->[7]->[10]->
    tRCs[3]  = tTRCs[3];
    tRCs[4]  = tTRCs[4];
    tRCs[7]  = tTRCs[7];
    tRCs[10] = tTRCs[10];
    break;
  case 1: // channels: ->[0]->[3]->[4]->[7]->
    tRCs[0] = tTRCs[0];
    tRCs[3] = tTRCs[3];
    tRCs[4] = tTRCs[4];
    tRCs[7] = tTRCs[7];
    break;
  case 2: // channels: ->[1]->[3]->[4]->[7]->
    tRCs[1] = tTRCs[1];
    tRCs[3] = tTRCs[3];
    tRCs[4] = tTRCs[4];
    tRCs[7] = tTRCs[7];
    break;
  case 3: // channels: ->[2]->[3]->[4]->[7]->[10]->
    tRCs[2]  = tTRCs[2];
    tRCs[3]  = tTRCs[3];
    tRCs[4]  = tTRCs[4];
    tRCs[7]  = tTRCs[7];
    tRCs[10] = tTRCs[10];
    break;
  case 4:  case 5:  case 6:  case 7: // channels: ->[4]->[7]->[10]->
    tRCs[4]  = tTRCs[4];
    tRCs[7]  = tTRCs[7];
    tRCs[10] = tTRCs[10];
    break;
  case 8:  case 9: // channels: ->[5]->[7]->[10]->
    tRCs[5]  = tTRCs[5];
    tRCs[7]  = tTRCs[7];
    tRCs[10] = tTRCs[10];
    break;
  case 10: case 11: // channels: ->[6]->[7]->[10]->
    tRCs[6]  = tTRCs[6];
    tRCs[7]  = tTRCs[7];
    tRCs[10] = tTRCs[10];
    break;
  case 12: // channels: ->[8]->[10]->
    tRCs[8]  = tTRCs[8];
    tRCs[10] = tTRCs[10];
    break;
  case 13: // channels: ->[9]->[10]->
    tRCs[9]  = tTRCs[9];
    tRCs[10] = tTRCs[10];
    break;
  default:
    qFatal("error in clearingOfChannels(): лидер неизвестного потока.");
  }
}

/*
  Расчет задержки коммутации сообщений
*/
double messageSwitchingDelay()
{
  QVector<double> &tMs  = networkSettings.timeMessages;
  QVector<double> &sMs  = networkSettings.sizeOfMessages;
  QVector<int>    &nTPs = networkSettings.numberOfTransferredPackets;
  int             &cF   = inputData.controlledFlow;

  double totalTime        = 0.0; // общее время работы сети
  double totalSize        = 0.0; // общий размер переданных данных
  int    numberOfMessages = 0;   // число сообщений переданных контролируемым потоком
  int    flowLeader       = -1;  // номер потока занявшего сеть

  while (numberOfMessages < inputData.limitMessages) {
    totalLeaderMS(&flowLeader); // поиск лидера

    ++nTPs[flowLeader];               // передать лидирующий пакет
    clearingOfChannelsMS(flowLeader); // освобождение занятых каналов

    // расчет задержки
    if (flowLeader == cF) {
      totalSize += sMs[cF];
      totalTime += networkSettings.currentTime - tMs[cF];
      ++numberOfMessages;

      // вывести задержку на половине пути
      if (numberOfMessages == inputData.limitMessages / 2) {
        cout << "(половина) задержка коммутации пакетов:\t\t"
             << totalTime / numberOfMessages << endl;
        cout << "(половина) средний размер сообщений:\t\t"
             << totalSize / numberOfMessages << endl;
      }
    }

    // формирование нового сообщения
    tMs[flowLeader] += conversion(inputData.intensity);
    sMs[flowLeader]  = conversion(inputData.messageLength);
  }

  cout << "\nзадержка коммутации пакетов:\t\t\t" << totalTime / numberOfMessages << endl;
  cout << "средний размер сообщений:\t\t\t" << totalSize / numberOfMessages << "\n\n";

  return totalTime / numberOfMessages;
}
